﻿using Furion.DatabaseAccessor;
using Furion.DependencyInjection;
using Furion.DynamicApiController;
using Furion.FriendlyException;
using iWare.Wms.Core;
using Mapster;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Serilog;
using Yitter.IdGenerator;

namespace iWare.Wms.Application
{
    /// <summary>
    /// 伟本LES WCS调用服务
    /// </summary>
    [ApiDescriptionSettings("伟本LES WCS调用服务", Name = "WareWcsToWmsService", Order = 100)]
    [Route("api/[Controller]")]
    public class WareWcsToWmsService : IDynamicApiController, ITransient
    {
        private readonly IRepository<WareTask, MasterDbContextLocator> _wareTask;
        private readonly IRepository<WareContainerVsMaterial, MasterDbContextLocator> _wareContainerVsMaterial;
        private readonly IRepository<WareAgvTask, MasterDbContextLocator> _wareAgvTask;
        private readonly IRepository<WareLocation, MasterDbContextLocator> _wareLocation;
        private readonly IRepository<WareLocationVsContainer, MasterDbContextLocator> _wareLocationVsContainer;
        private readonly IRepository<WareStock, MasterDbContextLocator> _wareStock;
        private readonly IRepository<WareContainer, MasterDbContextLocator> _wareContainer;
        private readonly IRepository<WareSortOrder, MasterDbContextLocator> _wareSortOrderRep;
        private readonly AgvService _agvService; //AGV服务

        /// <summary>
        /// 构造函数
        /// </summary>
        public WareWcsToWmsService(
            IRepository<WareTask, MasterDbContextLocator> wareTask,
        IRepository<WareContainerVsMaterial, MasterDbContextLocator> wareContainerVsMaterial,
        IRepository<WareAgvTask, MasterDbContextLocator> wareAgvTask,
        IRepository<WareLocation, MasterDbContextLocator> wareLocation,
        IRepository<WareLocationVsContainer, MasterDbContextLocator> wareLocationVsContainer,
        IRepository<WareStock, MasterDbContextLocator> wareStock,
        IRepository<WareContainer, MasterDbContextLocator> wareContainer,
        IRepository<WareSortOrder, MasterDbContextLocator> wareSortOrderRep,
        AgvService agvService
        )
        {
            _wareTask = wareTask;
            _wareContainerVsMaterial = wareContainerVsMaterial;
            _wareAgvTask = wareAgvTask;
            _wareLocation = wareLocation;
            _wareLocationVsContainer = wareLocationVsContainer;
            _wareStock = wareStock;
            _wareContainer = wareContainer;
            _wareSortOrderRep = wareSortOrderRep;
            _agvService = agvService;
        }

        /// <summary>
        /// 定时查询两条WMS可以下发的出入库任务(一条立库，一条平库)
        /// </summary>
        /// <returns></returns>
        [HttpGet("GetSendTask")]
        [AllowAnonymous]
        public async Task<List<SendTaskDetailOutput>> GetSendTask()
        {
            //获取立库
            var taskList = new List<SendTaskDetailOutput>();
            var lktaskModel = await _wareTask.DetachedEntities.OrderByDescending(z => z.Priority).FirstOrDefaultAsync(z => z.IsRead == true && z.ContainerCode.StartsWith("TJ"));
            if (lktaskModel != null)
            {
                //判断给到的是出库任务，需要判断内侧(2,3)是否也需要出库  外侧（1,4）
                int ncRowNumber = 0;
                if (lktaskModel.TaskType == TaskType.Out)
                {
                    var rowNumber = Convert.ToInt32(lktaskModel.FromLocationCode.Substring(4, 1));
                    if (rowNumber == 1) ncRowNumber = 2;
                    if (rowNumber == 4) ncRowNumber = 3;
                    var ncFromLocationCode = lktaskModel.FromLocationCode.Replace("W1L0" + rowNumber, "W1L0" + ncRowNumber);
                    var ncTaskModel = await _wareTask.FirstOrDefaultAsync(n => n.FromLocationCode == ncFromLocationCode && n.IsRead == true);
                    if (ncTaskModel != null)
                    {
                        var nclktask = ncTaskModel.Adapt<SendTaskDetailOutput>();
                        nclktask.IsLOrP = YesOrNot.N;
                        taskList.Add(nclktask);
                    }
                }
                var lktask = lktaskModel.Adapt<SendTaskDetailOutput>();
                lktask.IsLOrP = YesOrNot.N;
                taskList.Add(lktask);
            }

            //获取平库
            var pktaskModel = await _wareTask.FirstOrDefaultAsync(z => z.IsRead == true && z.ContainerCode.StartsWith("P"));
            if (pktaskModel != null)
            {
                var pktask = pktaskModel.Adapt<SendTaskDetailOutput>();
                pktask.IsLOrP = YesOrNot.Y;
                taskList.Add(pktask);
            }
            return taskList;
        }

        /// <summary>
        /// 获取库位信息
        /// </summary>
        /// <returns></returns>
        [HttpPost("GetPlace")]
        [UnitOfWork]
        [AllowAnonymous]
        public async Task<GetPlaceOutput> GetPlace([FromBody] GetPlaceInput input)
        {
            var taskModel = await _wareTask.Where(p => p.TaskNo == input.TaskNo).FirstOrDefaultAsync();
            if (taskModel == null) return new GetPlaceOutput() { TaskIsExist = false };
            //定义入库对象,移库对象
            var ToPlace = new WareLocation();
            var SourcePlace = new WareLocation();
            int rowNumber = 0;
            var height = input.High;
            //执行平库操作
            if (taskModel.ContainerCode.StartsWith("P") && !string.IsNullOrEmpty(taskModel.Weight))
            {
                //根据重量和高度进行库位分配
                var pklocationModel = await _wareLocation.Where(p => p.AreaID == 374444736143429 && p.Attribute == height && p.LocationStatus == LocationStatusEnum.kongxian && p.IsLock == YesOrNot.N).OrderBy(p => p.LayerNo).FirstOrDefaultAsync();

                //await _wareLocation.Where(p => p.AreaID == 374444736143429 && p.Attribute == height && p.Heavy == taskModel.Weight && p.LocationStatus == LocationStatusEnum.kongxian && p.IsLock == YesOrNot.N).OrderBy(p => p.LayerNo).FirstOrDefaultAsync();
                if (pklocationModel == null)
                {
                    //pklocationModel = await _wareLocation.Where(p => p.AreaID == 374444736143429 && p.Attribute == height && p.LocationStatus == LocationStatusEnum.kongxian && p.IsLock == YesOrNot.N).OrderBy(p => p.LayerNo).FirstOrDefaultAsync();

                    //中库位不够则分配大库位
                    if (pklocationModel == null && input.High == "中") pklocationModel = await _wareLocation.Where(p => p.AreaID == 374444736143429 && p.Attribute == "大" && p.LocationStatus == LocationStatusEnum.kongxian && p.IsLock == YesOrNot.N).FirstOrDefaultAsync();

                    //小库位不够则分配中，大库位
                    if (pklocationModel == null && input.High == "小") pklocationModel = await _wareLocation.Where(p => p.AreaID == 374444736143429 && (p.Attribute == "中" || p.Attribute == "大") && p.LocationStatus == LocationStatusEnum.kongxian && p.IsLock == YesOrNot.N).OrderBy(p => p.LayerNo).FirstOrDefaultAsync();
                }

                //if(pklocationModel == null) throw Oops.Oh(errorMessage: "暂无可用库位信息！");

                if (pklocationModel != null)
                {
                    taskModel.IsRead = false;
                    taskModel.ToLocationCode = pklocationModel.Code;
                    await _wareTask.UpdateAsync(taskModel);
                    //修改库位信息为待入
                    pklocationModel.LocationStatus = LocationStatusEnum.dairu;
                    await _wareLocation.UpdateAsync(pklocationModel);


                    //根据库位获取对应的放货层
                    var layNumber = 0;
                    if (pklocationModel.RowNo == 6)
                    {
                        if (pklocationModel.LayerNo == 5) layNumber = pklocationModel.LayerNo + 6;
                        else layNumber = pklocationModel.LayerNo + 5;

                    }
                    else
                    {
                        if (pklocationModel.LayerNo == 1) layNumber = pklocationModel.LayerNo - 1;
                        else layNumber = pklocationModel.LayerNo;
                    }
                    //创建第二段AGV任务
                    var agvModel = new CreateOrdersedInput()
                    {
                        TaskNo = taskModel.TaskNo + "-2",
                        locationName = pklocationModel.OriginalLocationCode,
                        operation = "Unload cargo:" + layNumber.ToString("00")
                    };
                    var createTransportOrdersOutput = await _agvService.CreateUnloadOrders(agvModel);

                    if (createTransportOrdersOutput.result == "success")
                    {
                        // 创建AGV入库任务
                        var wareAgvTask = new WareAgvTask()
                        {
                            TaskType = "入库",
                            StartPlace = "9067", //地面站点/上料口
                            EndPlace = pklocationModel.Code, //平库原库位编号
                            TransportOrder = taskModel.TaskNo,
                            AgvState = "TRAVELLING",
                            ContainerCode = taskModel.ContainerCode,
                            CreatedUserName = taskModel.CreatedUserName,
                        };
                        await _wareAgvTask.InsertAsync(wareAgvTask);
                    }
                }

                return new GetPlaceOutput()
                {
                    ToPlace = ToPlace.Code,
                    SourcePlace = SourcePlace.Code
                };
            }
            //入库流程
            if (taskModel.TaskType == TaskType.In)
            {
                if (string.IsNullOrEmpty(input.High)) throw Oops.Oh(errorMessage: "获取货物高度不能为空！");
                var allLocation = new List<WareLocation>();
                //获取所有满足条件的库区-立体库
                if (height == "大")
                {
                    allLocation = await _wareLocation.Where(p => p.AreaID == 374444843716677 && p.Attribute == "大" && p.LocationStatus == LocationStatusEnum.kongxian && p.IsLock == YesOrNot.N).OrderBy(p => p.LayerNo).ToListAsync();
                }
                else if (height == "中")
                {
                    allLocation = await _wareLocation.Where(p => p.AreaID == 374444843716677 && (p.Attribute == "中" || p.Attribute == "大") && p.LocationStatus == LocationStatusEnum.kongxian && p.IsLock == YesOrNot.N).OrderBy(p => p.LayerNo).ToListAsync();
                }
                else
                {
                    allLocation = await _wareLocation.Where(p => p.AreaID == 374444843716677 && p.LocationStatus == LocationStatusEnum.kongxian && p.IsLock == YesOrNot.N).OrderBy(p => p.LayerNo).ToListAsync();
                }
                if (allLocation.Count <= 1) throw Oops.Oh(errorMessage: "暂无可用库位信息！");

                //防重操作
                if (taskModel.ToLocationCode != "N/A" && !string.IsNullOrEmpty(taskModel.ToLocationCode))
                {
                    int ncRowNumber = 0;
                    rowNumber = Convert.ToInt32(taskModel.ToLocationCode.Substring(4, 1));
                    if (rowNumber == 1) ncRowNumber = 2;
                    if (rowNumber == 4) ncRowNumber = 3;
                    var ncFromLocationCode = taskModel.ToLocationCode.Replace("W1L0" + rowNumber, "W1L0" + ncRowNumber);
                    SourcePlace = await _wareLocation.FirstOrDefaultAsync(p => p.Code == ncFromLocationCode && p.LocationStatus == LocationStatusEnum.cunhuo) ?? new WareLocation();

                    return new GetPlaceOutput()
                    {
                        ToPlace = taskModel.ToLocationCode,
                        SourcePlace = SourcePlace.Code
                    };
                }
                //获取所有的出库任务
                var allckTaskList = await _wareTask.Where(z => z.IsRead == true && z.TaskType == TaskType.Out).ToListAsync();
                //优先外侧无货库位，再内侧，最后考虑移库 在考虑是否需要移库
                var cylocation = new List<WareLocation>();
                var wclocation = allLocation.Where(p => (p.RowNo == 1 || p.RowNo == 4)).ToList();

                foreach (var item in wclocation)
                {
                    if (item.RowNo == 1) rowNumber = 2;
                    if (item.RowNo == 4) rowNumber = 3;
                    var ncModel = allLocation.FirstOrDefault(p => p.RowNo == rowNumber && p.ColumnNo == item.ColumnNo && p.LayerNo == item.LayerNo);
                    if (ncModel != null)
                    {
                        ToPlace = item;
                        break;
                    }
                    else cylocation.Add(ncModel);
                }
                //二优考虑内侧库位,
                var nclocation = allLocation.Where(p => (p.RowNo == 2 || p.RowNo == 3)).ToList();
                if (nclocation.Count > 1 && string.IsNullOrWhiteSpace(ToPlace.Code))
                {
                    int wcRowNumber = 0;
                    //需要判断外侧是否有出库任务
                    foreach (var item in nclocation)
                    {
                        rowNumber = 0;
                        if (rowNumber == 2) wcRowNumber = 1;
                        if (rowNumber == 3) wcRowNumber = 4;
                        var wcFromLocationCode = item.Code.Replace("W1L0" + rowNumber, "W1L0" + wcRowNumber);
                        var wcTaskModel = allckTaskList.FirstOrDefault(n => n.FromLocationCode == wcFromLocationCode && n.IsRead == true);
                        if (wcTaskModel != null)
                        {
                            continue;
                        }
                        ToPlace = item;
                    }
                }

                if (string.IsNullOrWhiteSpace(ToPlace.Code))
                {
                    //最后考虑外侧库位对应的内侧进行移库操作
                    foreach (var item in cylocation)
                    {
                        if (item.RowNo == 1) rowNumber = 2;
                        if (item.RowNo == 4) rowNumber = 3;
                        SourcePlace = await _wareLocation.FirstOrDefaultAsync(p => p.RowNo == rowNumber && p.ColumnNo == item.ColumnNo && p.LayerNo == item.LayerNo && p.AreaID == 374444843716677);
                        //需要判断移库库位是否有出库任务
                        if (SourcePlace != null)
                        {
                            var ckTaskModel = allckTaskList.FirstOrDefault(n => n.FromLocationCode == SourcePlace.Code && n.IsRead == true);
                            if (ckTaskModel != null) continue;
                        }
                        ToPlace = item;
                        break;
                    }
                }
                //更新库位和任务状态
                ToPlace.LocationStatus = LocationStatusEnum.dairu;
                await _wareLocation.UpdateAsync(ToPlace);
                taskModel.ToLocationCode = ToPlace.Code;
                await _wareTask.UpdateAsync(taskModel);

                return new GetPlaceOutput()
                {
                    ToPlace = ToPlace.Code,
                    SourcePlace = SourcePlace.Code
                };
            }
            //出库流程
            if (taskModel.TaskType == TaskType.Out)
            {
                ToPlace = await _wareLocation.FirstOrDefaultAsync(n => n.Code == taskModel.FromLocationCode);
                if (ToPlace.RowNo == 1) rowNumber = 2;
                if (ToPlace.RowNo == 4) rowNumber = 3;
                //外侧需要内侧是否货，有货需要移库
                var ncLocationModel = await _wareLocation.FirstOrDefaultAsync(p => p.RowNo == rowNumber && p.ColumnNo == ToPlace.ColumnNo && p.LayerNo == ToPlace.LayerNo && p.LocationStatus == LocationStatusEnum.cunhuo && p.AreaID == 374444843716677);
                if (ncLocationModel != null) SourcePlace = ncLocationModel;

                //更新库位信息
                ToPlace.LocationStatus = LocationStatusEnum.daichu;
                await _wareLocation.UpdateAsync(ToPlace);

                return new GetPlaceOutput()
                {
                    ToPlace = ToPlace.Code,
                    SourcePlace = SourcePlace.Code
                };
            }
            else
            {
                throw Oops.Oh("任务异常" + taskModel.TaskNo);
            }
        }

        /// <summary>
        /// 更新任务信息
        /// </summary>
        /// <returns></returns>
        [HttpPost("UpdateTask")]
        [UnitOfWork]
        [AllowAnonymous]
        public async Task UpdateTask([FromBody] UpdateTaskInput input)
        {
            // 写日志文件
            Log.Error("[UpdateTaskWcs接口]接收参数:" + input.ToJson());

            // 根据任务号查询任务信息
            var wmsTask = await _wareTask.FirstOrDefaultAsync(z => z.TaskNo == input.TaskNo && z.TaskStatus != TaskStatusEnum.Complete);
            if (wmsTask == null) throw Oops.Oh(errorMessage: "任务不存在或已完成！");
            wmsTask.TaskStatus = TaskStatusEnum.Progress;
            wmsTask.IsRead = false;
            // 查询托盘信息
            var wmsContainer = await _wareContainer.FirstOrDefaultAsync(z => z.Code == wmsTask.ContainerCode);
            if (wmsContainer == null) throw Oops.Oh("托盘不存在！");
            //入库完成
            if (wmsTask.TaskType == TaskType.In && input.TaskStatus == TaskStatusEnum.Complete)
            {
                wmsTask.TaskStatus = TaskStatusEnum.Complete;
                //库位信息
                var wmsPlace = await _wareLocation.DetachedEntities.Where(z => z.Code == wmsTask.ToLocationCode).ProjectToType<WareLocation>().FirstOrDefaultAsync();
                //构建托盘库位关系表
                await _wareLocationVsContainer.InsertAsync(new WareLocationVsContainer()
                {
                    LocationId = wmsPlace.Id,
                    LocationCode = wmsPlace.Code,
                    ContainerId = wmsContainer.Id,
                    ContainerCode = wmsContainer.Code,
                    LocationVsContainerStatus = CommonStatus.ENABLE
                });
                //物料托盘关系表
                var wmsMaterialContainerList = await _wareContainerVsMaterial.DetachedEntities
                    .Where(p => p.OrderNo == wmsTask.OrderNo).ToListAsync();
                //更新库存
                foreach (var item in wmsMaterialContainerList)
                {
                    // 更新库存
                    var stockDetailModel = await _wareStock.FirstOrDefaultAsync(n => n.ContainerCode == item.ContainerCode
                    && n.Code == item.Code && n.SpecificationModel == item.SpecificationModel);

                    if (stockDetailModel != null)
                    {
                        stockDetailModel.StockQuantity = item.BindQuantity;
                        stockDetailModel.LocationCode = wmsTask.ToLocationCode;
                        stockDetailModel.CurrentQuantity = item.BindQuantity;
                        stockDetailModel.ProjectCode = item.ProjectCode;
                        stockDetailModel.ExpirationTime = item.ExpirationTime;
                        await _wareStock.UpdateAsync(stockDetailModel);
                    }
                    else
                    {
                        stockDetailModel = new WareStock()
                        {
                            ProjectCode = item.ProjectCode,
                            Code = item.Code,
                            Name = item.Name,
                            SpecificationModel = item.SpecificationModel,
                            Unit = item.Unit,
                            StockQuantity = item.BindQuantity,
                            CurrentQuantity = item.BindQuantity,
                            ContainerCode = item.ContainerCode,
                            LocationCode = wmsTask.ToLocationCode,
                            XuHao = item.XuHao,
                            BrandName = item.BrandName,
                            ExpirationTime = item.ExpirationTime,
                            UpdatedUserId = wmsTask.CreatedUserId,
                            UpdatedUserName = wmsTask.CreatedUserName,
                            UpdatedTime = DateTimeOffset.Now
                        };
                        await _wareStock.InsertAsync(stockDetailModel);
                    }
                }
                // 更新库位状态
                wmsPlace.LocationStatus = LocationStatusEnum.cunhuo;
                await _wareLocation.UpdateAsync(wmsPlace);

                // 更新托盘状态为“库位”
                wmsContainer.ContainerStatus = ContainerStatusEnum.kuwei;
                await _wareContainer.UpdateAsync(wmsContainer);


                var LontionMode  = await _wareLocation.FirstOrDefaultAsync(z => z.Code == wmsTask.FromLocationCode && z.LocationStatus == LocationStatusEnum.daichu);
                if(LontionMode != null && wmsTask.TaskModel == TaskModel.ZIDONG)
                {
                    //删除agv分拣库位容器关系
                    var LontionVSContion = await _wareLocationVsContainer.FirstOrDefaultAsync(z => z.LocationCode == LontionMode.Code && z.LocationVsContainerStatus == CommonStatus.ENABLE);
                    if (LontionVSContion == null) throw Oops.Oh("AGV分拣库位关系不存在!");
                    await _wareLocationVsContainer.DeleteAsync(LontionVSContion);
                    //更新agv分拣库位关系
                    LontionMode.LocationStatus = LocationStatusEnum.kongxian;
                    await _wareLocation.UpdateAsync(LontionMode);
                }

            }
            //出库堆垛机完成,执行库存，库位，托盘对应关系进行更新
            else if (wmsTask.TaskType == TaskType.Out && input.TaskStatus == TaskStatusEnum.Complete)
            {
                if (wmsTask.TaskModel == TaskModel.ZIDONG)
                {
                    // 调用AGV服务创建指定名称的订单
                    var createTransportOrders = new CreateTransportOrdersInput();
                    createTransportOrders.TaskNo = wmsTask.TaskNo;
                    createTransportOrders.intendedVehicle = "Vehicle-0001"; //立体库执行车辆
                    var destList = new List<DestinationsInput>();
                    var dest1 = new DestinationsInput()
                    {
                        locationName = "Location-0015", //输送线
                        operation = "Load cargo:01" //输送线层数是1
                    };
                    var dest2 = new DestinationsInput()
                    {
                        locationName = wmsTask.ToLocationCode, //分拣库位编码
                        operation = "Unload cargo:12" //地面层数是12
                    };
                    destList.Add(dest1);
                    destList.Add(dest2);
                    createTransportOrders.destinations = destList;

                    var createTransportOrdersOutput = await _agvService.CreateTransportOrders(createTransportOrders);

                    if (createTransportOrdersOutput.result == "success")
                    {
                        // 创建AGV入库任务
                        var wareAgvTask = new WareAgvTask()
                        {
                            TaskType = "出库",
                            StartPlace = wmsTask.FromLocationCode, //地面站点/上料口
                            EndPlace = wmsTask.ToLocationCode, //[Location-0016]入库对应的输送线
                            TransportOrder = wmsTask.TaskNo,
                            AgvState = "TRAVELLING",
                            ContainerCode = wmsTask.ContainerCode,
                            CreatedUserId = wmsTask.CreatedUserId,
                            CreatedUserName = wmsTask.CreatedUserName
                        };
                        await _wareAgvTask.InsertAsync(wareAgvTask);
                    }

                    //// 查询托盘与库位的关系
                    //var wmsContainerPlace = await _wareLocationVsContainer.FirstOrDefaultAsync(z => z.ContainerCode == wmsTask.ContainerCode && z.LocationVsContainerStatus == CommonStatus.ENABLE);
                    //if (wmsContainerPlace == null) throw Oops.Oh("库位容器关系不存在!");

                    //// 禁用托盘库位关系
                    //wmsContainerPlace.LocationVsContainerStatus = CommonStatus.DELETED;
                    //await _wareLocationVsContainer.UpdateAsync(wmsContainerPlace);
                }
                else
                {
                    wmsTask.TaskStatus = TaskStatusEnum.Complete;

                    // 查询库位信息
                    var wmsPlace = await _wareLocation.FirstOrDefaultAsync(z => z.Code == wmsTask.FromLocationCode);
                    if (wmsPlace == null) throw Oops.Oh("库位不存在!");
                    // 查询托盘与库位的关系
                    var wmsContainerPlace = await _wareLocationVsContainer.FirstOrDefaultAsync(z => z.LocationId == wmsPlace.Id && z.LocationCode == wmsPlace.Code
                    && z.ContainerCode == wmsTask.ContainerCode && z.LocationVsContainerStatus == CommonStatus.ENABLE);
                    if (wmsContainerPlace == null) throw Oops.Oh("库位容器关系不存在!");

                    var wmsMaterialContainer = await _wareContainerVsMaterial.Where(p => p.ContainerCode == wmsTask.ContainerCode
                    && p.ContainerVsMaterialStatus == CommonStatus.ENABLE).ToListAsync();

                    //清除库存对应库位
                    //修改库存
                    var materialStockList = await _wareStock.Where(n => n.ContainerCode == wmsTask.ContainerCode
                    && n.LocationCode == wmsTask.FromLocationCode).ToListAsync();
                    foreach (var item in materialStockList)
                    {
                        item.LocationCode = "N/A";
                        await _wareStock.UpdateAsync(item);
                    }
                    foreach (var item in wmsMaterialContainer)
                    {
                        item.ContainerVsMaterialStatus = CommonStatus.DELETED;
                        await _wareContainerVsMaterial.UpdateAsync(item);
                        //新增正常新的组盘关系
                        var enableModel = new WareContainerVsMaterial()
                        {
                            ContainerId = item.ContainerId,
                            ContainerCode = item.ContainerCode,
                            ProjectCode = item.ProjectCode,
                            XuHao = item.XuHao,
                            Code = item.Code,
                            Name = item.Name,
                            SpecificationModel = item.SpecificationModel,
                            Unit = item.Unit,
                            InspectionMethod = item.InspectionMethod,
                            BrandName = item.BrandName,
                            MaterialId = item.MaterialId,
                            BindQuantity = item.BindQuantity,
                            ExpirationTime = item.ExpirationTime,
                            ContainerVsMaterialStatus = CommonStatus.ENABLE,
                            OrderNo = YitIdHelper.NextId().ToString()
                        };
                        await _wareContainerVsMaterial.InsertNowAsync(enableModel);
                    }
                    // 禁用托盘库位关系
                    wmsContainerPlace.LocationVsContainerStatus = CommonStatus.DELETED;
                    await _wareLocationVsContainer.UpdateAsync(wmsContainerPlace);
                    // 更新库位状态为“空闲”
                    wmsPlace.LocationStatus = LocationStatusEnum.kongxian;
                    await _wareLocation.UpdateAsync(wmsPlace);
                    // 更新托盘状态为“分拣”或“组盘”
                    var isExit = await _wareSortOrderRep.AnyAsync(p => p.ContainerCode == wmsContainer.Code && p.SortStatus != SortStatusEnum.Completed);
                    if (isExit)
                    {
                        wmsContainer.ContainerStatus = ContainerStatusEnum.fenjian;
                    }
                    else
                    {
                        wmsContainer.ContainerStatus = ContainerStatusEnum.zupan;
                    }
                    await _wareContainer.UpdateAsync(wmsContainer);
                }
            }
            else //移库
            {
                if (wmsTask.TaskType == TaskType.Move && input.TaskStatus == TaskStatusEnum.Complete)
                {
                    wmsTask.TaskStatus = TaskStatusEnum.Complete;
                    // 起点库位信息
                    var SourcePlace = await _wareLocation.Where(z => z.Code == wmsTask.FromLocationCode).FirstOrDefaultAsync();
                    SourcePlace.LocationStatus = LocationStatusEnum.kongxian;
                    await _wareLocation.UpdateAsync(SourcePlace);
                    //目标库位信息
                    var ToPlace = await _wareLocation.Where(z => z.Code == wmsTask.ToLocationCode).FirstOrDefaultAsync();
                    ToPlace.LocationStatus = LocationStatusEnum.cunhuo;
                    await _wareLocation.UpdateAsync(ToPlace);
                    //托盘库位关系表
                    var wmsContainerPlace = await _wareLocationVsContainer.FirstOrDefaultAsync(z => z.LocationId == SourcePlace.Id && z.LocationCode == SourcePlace.Code
                    && z.ContainerCode == wmsTask.ContainerCode && z.LocationVsContainerStatus == CommonStatus.ENABLE);
                    wmsContainerPlace.LocationVsContainerStatus = CommonStatus.DELETED;
                    await _wareLocationVsContainer.UpdateAsync(wmsContainerPlace);
                    await _wareLocationVsContainer.InsertAsync(new WareLocationVsContainer()
                    {
                        LocationId = ToPlace.Id,
                        LocationCode = ToPlace.Code,
                        ContainerId = wmsContainer.Id,
                        ContainerCode = wmsContainer.Code,
                        LocationVsContainerStatus = CommonStatus.ENABLE
                    });
                    //库存库位更新
                    var stockModel = await _wareStock.Where(p => p.ContainerCode == wmsTask.ContainerCode && p.LocationCode == SourcePlace.Code).ToListAsync();
                    foreach (var item in stockModel)
                    {
                        item.LocationCode = ToPlace.Code;
                        await _wareStock.UpdateAsync(item);
                    }
                }
            }

            await _wareTask.UpdateAsync(wmsTask);
        }

        /// <summary>
        /// 创建移库任务
        /// </summary>
        /// <returns></returns>
        [HttpPost("CreateYKTask")]
        [UnitOfWork]
        [AllowAnonymous]
        public async Task<GetYiKuPlaceOutput> CreateRelocation(CreateRelocationInput input)
        {
            var placeModel = await _wareLocation.Where(p => p.Code == input.SourcePlace).ProjectToType<WareLocation>().FirstOrDefaultAsync();
            if (placeModel == null) throw Oops.Oh("库位数据异常!");
            placeModel.LocationStatus = LocationStatusEnum.daichu;
            await _wareLocation.UpdateAsync(placeModel);
            //查询组盘单据
            var containerPlaceModel = await _wareLocationVsContainer.Where(p => p.LocationCode == input.SourcePlace && p.LocationVsContainerStatus == CommonStatus.ENABLE).FirstOrDefaultAsync();
            if (containerPlaceModel == null) throw Oops.Oh("移库库位托盘数据异常!");
            var materialContainer = await _wareContainerVsMaterial.Where(p => p.ContainerCode == containerPlaceModel.ContainerCode && p.ContainerVsMaterialStatus == CommonStatus.ENABLE).FirstOrDefaultAsync();
            if (materialContainer == null) throw Oops.Oh("组盘数据异常!");

            //获取空闲库位集合
            var placeList = new List<WareLocation>();

            if (placeModel.Attribute == "大")
            {
                placeList = await _wareLocation.Where(p => p.AreaID == 374444843716677 && p.Attribute == "大" && p.LocationStatus == LocationStatusEnum.kongxian && p.IsLock == YesOrNot.N).OrderByDescending(p => p.High).ToListAsync();
            }
            else if (placeModel.Attribute == "中")
            {
                placeList = await _wareLocation.Where(p => p.AreaID == 374444843716677 && (p.Attribute == "中" || p.Attribute == "大") && p.LocationStatus == LocationStatusEnum.kongxian && p.IsLock == YesOrNot.N).OrderByDescending(p => p.High).ToListAsync();
            }
            else
            {
                placeList = await _wareLocation.Where(p => p.AreaID == 374444843716677 && p.LocationStatus == LocationStatusEnum.kongxian && p.IsLock == YesOrNot.N).OrderByDescending(p => p.High).ToListAsync();
            }
            if (placeList.Count == 0) throw Oops.Oh("无可移库库位!");

            //定义目标点
            var ToPlaceModel = new WareLocation();
            //获取所有的出库任务
            var allckTaskList = await _wareTask.Where(z => z.IsRead == true && z.TaskType == TaskType.Out).ToListAsync();
            //优先外侧无货库位，再内侧，最后考虑移库 在考虑是否需要移库
            var cylocation = new List<WareLocation>();
            var wclocation = placeList.Where(p => (p.RowNo == 1 || p.RowNo == 4)).ToList();
            int rowNumber = 0;
            foreach (var item in wclocation)
            {
                if (item.RowNo == 1) rowNumber = 2;
                if (item.RowNo == 4) rowNumber = 3;
                var ncModel = placeList.FirstOrDefault(p => p.RowNo == rowNumber && p.ColumnNo == item.ColumnNo && p.LayerNo == item.LayerNo);
                if (ncModel != null)
                {
                    ToPlaceModel = item;
                    break;
                }
                else cylocation.Add(ncModel);
            }
            //二优考虑内侧库位,
            var nclocation = placeList.Where(p => (p.RowNo == 2 || p.RowNo == 3)).ToList();
            if (nclocation.Count > 1 && string.IsNullOrWhiteSpace(ToPlaceModel.Code))
            {
                int wcRowNumber = 0;
                //需要判断外侧是否有出库任务
                foreach (var item in nclocation)
                {
                    rowNumber = 0;
                    if (rowNumber == 2) wcRowNumber = 1;
                    if (rowNumber == 3) wcRowNumber = 4;
                    var wcFromLocationCode = item.Code.Replace("W1L0" + rowNumber, "W1L0" + wcRowNumber);
                    var wcTaskModel = allckTaskList.FirstOrDefault(n => n.FromLocationCode == wcFromLocationCode && n.IsRead == true);
                    if (wcTaskModel != null)
                    {
                        continue;
                    }
                    ToPlaceModel = item;
                }
            }
            ToPlaceModel.LocationStatus = LocationStatusEnum.dairu;
            await _wareLocation.UpdateAsync(ToPlaceModel);

            var taskNo = YitIdHelper.NextId().ToString(); //系统生成任务号
            var taskModel = new WareTask()
            {
                OrderNo = materialContainer.OrderNo,
                TaskNo = taskNo,
                TaskType = TaskType.Move,
                TaskModel = TaskModel.ZIDONG,
                TaskName = TaskNameConst.Litiku_AutomaticIn,
                TaskStatus = TaskStatusEnum.Progress,
                Priority = 1,
                ContainerCode = containerPlaceModel.ContainerCode,
                FromLocationCode = input.SourcePlace, //入口
                ToLocationCode = ToPlaceModel.Code,
                CreatedUserName = "WMS"
            };
            await _wareTask.InsertAsync(taskModel);

            return new GetYiKuPlaceOutput()
            {
                ToPlace = ToPlaceModel.Code,
                TaskNo = taskModel.TaskNo,
            };
        }


        /// <summary>
        /// 完成任务
        /// </summary>
        /// <returns></returns>
        [HttpPost("Finish")]
        [UnitOfWork]
        [AllowAnonymous]
        public async Task Finish([FromBody] FinishTaskInput input)
        {
            // 写日志文件
            Log.Error("[Finish]接收参数:" + input.ToJson());

            // 根据任务号查询任务信息
            var wmsTask = await _wareTask.FirstOrDefaultAsync(z => z.TaskNo == input.TaskNo);
            if (wmsTask == null) throw Oops.Oh(errorMessage: "任务不存在或已完成！");
            wmsTask.IsRead = false;
            // 查询托盘信息
            var wmsContainer = await _wareContainer.FirstOrDefaultAsync(z => z.Code == wmsTask.ContainerCode);
            if (wmsContainer == null) throw Oops.Oh("托盘不存在！");
            //入库完成
            if (wmsTask.TaskType == TaskType.In)
            {
                wmsTask.TaskStatus = TaskStatusEnum.Complete;
                //库位信息
                var wmsPlace = await _wareLocation.DetachedEntities.Where(z => z.Code == wmsTask.ToLocationCode).ProjectToType<WareLocation>().FirstOrDefaultAsync();
                //构建托盘库位关系表
                await _wareLocationVsContainer.InsertAsync(new WareLocationVsContainer()
                {
                    LocationId = wmsPlace.Id,
                    LocationCode = wmsPlace.Code,
                    ContainerId = wmsContainer.Id,
                    ContainerCode = wmsContainer.Code,
                    LocationVsContainerStatus = CommonStatus.ENABLE
                });
                //物料托盘关系表
                var wmsMaterialContainerList = await _wareContainerVsMaterial.DetachedEntities
                    .Where(p => p.OrderNo == wmsTask.OrderNo).ToListAsync();
                //更新库存
                foreach (var item in wmsMaterialContainerList)
                {
                    // 更新库存
                    var stockDetailModel = await _wareStock.FirstOrDefaultAsync(n => n.ContainerCode == item.ContainerCode
                    && n.Code == item.Code && n.SpecificationModel == item.SpecificationModel);

                    if (stockDetailModel != null)
                    {
                        stockDetailModel.StockQuantity = item.BindQuantity;
                        stockDetailModel.LocationCode = wmsTask.ToLocationCode;
                        stockDetailModel.CurrentQuantity = item.BindQuantity;
                        stockDetailModel.ProjectCode = item.ProjectCode;
                        stockDetailModel.ExpirationTime = item.ExpirationTime;
                        await _wareStock.UpdateAsync(stockDetailModel);
                    }
                    else
                    {
                        stockDetailModel = new WareStock()
                        {
                            ProjectCode = item.ProjectCode,
                            Code = item.Code,
                            Name = item.Name,
                            SpecificationModel = item.SpecificationModel,
                            Unit = item.Unit,
                            StockQuantity = item.BindQuantity,
                            CurrentQuantity = item.BindQuantity,
                            ContainerCode = item.ContainerCode,
                            LocationCode = wmsTask.ToLocationCode,
                            XuHao = item.XuHao,
                            BrandName = item.BrandName,
                            ExpirationTime = item.ExpirationTime,
                        };
                        await _wareStock.InsertAsync(stockDetailModel);
                    }
                }
                // 更新库位状态
                wmsPlace.LocationStatus = LocationStatusEnum.cunhuo;
                await _wareLocation.UpdateAsync(wmsPlace);

                // 更新托盘状态为“库位”
                wmsContainer.ContainerStatus = ContainerStatusEnum.kuwei;
                await _wareContainer.UpdateAsync(wmsContainer);

            }
            //出库堆垛机完成,执行库存，库位，托盘对应关系进行更新
            else if (wmsTask.TaskType == TaskType.Out)
            {
                if (wmsTask.TaskModel == TaskModel.ZIDONG)
                {
                    // 调用AGV服务创建指定名称的订单
                    var createTransportOrders = new CreateTransportOrdersInput();
                    createTransportOrders.TaskNo = wmsTask.TaskNo;
                    createTransportOrders.intendedVehicle = "Vehicle-0001"; //立体库执行车辆
                    var destList = new List<DestinationsInput>();
                    var dest1 = new DestinationsInput()
                    {
                        locationName = "Location-0015", //输送线
                        operation = "Load cargo:01" //输送线层数是1
                    };
                    var dest2 = new DestinationsInput()
                    {
                        locationName = wmsTask.ToLocationCode, //分拣库位编码
                        operation = "Unload cargo:12" //地面层数是12
                    };
                    destList.Add(dest1);
                    destList.Add(dest2);
                    createTransportOrders.destinations = destList;

                    var createTransportOrdersOutput = await _agvService.CreateTransportOrders(createTransportOrders);

                    if (createTransportOrdersOutput.result == "success")
                    {
                        // 创建AGV入库任务
                        var wareAgvTask = new WareAgvTask()
                        {
                            TaskType = "出库",
                            StartPlace = wmsTask.FromLocationCode, //地面站点/上料口
                            EndPlace = wmsTask.ToLocationCode, //[Location-0016]入库对应的输送线
                            TransportOrder = wmsTask.TaskNo,
                            AgvState = "TRAVELLING",
                            ContainerCode = wmsTask.ContainerCode,
                        };
                        await _wareAgvTask.InsertAsync(wareAgvTask);
                    }
                }
                else
                {
                    wmsTask.TaskStatus = TaskStatusEnum.Complete;

                    // 查询库位信息
                    var wmsPlace = await _wareLocation.FirstOrDefaultAsync(z => z.Code == wmsTask.FromLocationCode);
                    if (wmsPlace == null) throw Oops.Oh("库位不存在!");
                    // 查询托盘与库位的关系
                    var wmsContainerPlace = await _wareLocationVsContainer.FirstOrDefaultAsync(z => z.LocationId == wmsPlace.Id && z.LocationCode == wmsPlace.Code
                    && z.ContainerCode == wmsTask.ContainerCode && z.LocationVsContainerStatus == CommonStatus.ENABLE);
                    if (wmsContainerPlace == null) throw Oops.Oh("库位容器关系不存在!");

                    var wmsMaterialContainer = await _wareContainerVsMaterial.Where(p => p.ContainerCode == wmsTask.ContainerCode
                    && p.ContainerVsMaterialStatus == CommonStatus.ENABLE).ToListAsync();

                    //清除库存对应库位
                    //修改库存
                    var materialStockList = await _wareStock.Where(n => n.ContainerCode == wmsTask.ContainerCode
                    && n.LocationCode == wmsTask.FromLocationCode).ToListAsync();
                    foreach (var item in materialStockList)
                    {
                        item.LocationCode = "N/A";
                        await _wareStock.UpdateAsync(item);
                    }
                    foreach (var item in wmsMaterialContainer)
                    {
                        item.ContainerVsMaterialStatus = CommonStatus.DELETED;
                        await _wareContainerVsMaterial.UpdateAsync(item);
                        //新增正常新的组盘关系
                        var enableModel = new WareContainerVsMaterial()
                        {
                            ContainerId = item.ContainerId,
                            ContainerCode = item.ContainerCode,
                            ProjectCode = item.ProjectCode,
                            XuHao = item.XuHao,
                            Code = item.Code,
                            Name = item.Name,
                            SpecificationModel = item.SpecificationModel,
                            Unit = item.Unit,
                            InspectionMethod = item.InspectionMethod,
                            BrandName = item.BrandName,
                            MaterialId = item.MaterialId,
                            BindQuantity = item.BindQuantity,
                            ContainerVsMaterialStatus = CommonStatus.ENABLE,
                            ExpirationTime = item.ExpirationTime,
                            OrderNo = YitIdHelper.NextId().ToString()
                        };
                        await _wareContainerVsMaterial.InsertNowAsync(enableModel);
                    }
                    // 禁用托盘库位关系
                    wmsContainerPlace.LocationVsContainerStatus = CommonStatus.DELETED;
                    await _wareLocationVsContainer.UpdateAsync(wmsContainerPlace);
                    // 更新库位状态为“空闲”
                    wmsPlace.LocationStatus = LocationStatusEnum.kongxian;
                    await _wareLocation.UpdateAsync(wmsPlace);
                    // 更新托盘状态为“组盘”
                    wmsContainer.ContainerStatus = ContainerStatusEnum.zupan;
                    await _wareContainer.UpdateAsync(wmsContainer);
                }
            }
            else //移库
            {
                if (wmsTask.TaskType == TaskType.Move)
                {
                    wmsTask.TaskStatus = TaskStatusEnum.Complete;
                    // 起点库位信息
                    var SourcePlace = await _wareLocation.Where(z => z.Code == wmsTask.FromLocationCode).FirstOrDefaultAsync();
                    SourcePlace.LocationStatus = LocationStatusEnum.kongxian;
                    await _wareLocation.UpdateAsync(SourcePlace);
                    //目标库位信息
                    var ToPlace = await _wareLocation.Where(z => z.Code == wmsTask.ToLocationCode).FirstOrDefaultAsync();
                    ToPlace.LocationStatus = LocationStatusEnum.cunhuo;
                    await _wareLocation.UpdateAsync(ToPlace);
                    //托盘库位关系表
                    var wmsContainerPlace = await _wareLocationVsContainer.FirstOrDefaultAsync(z => z.LocationId == SourcePlace.Id && z.LocationCode == SourcePlace.Code
                    && z.ContainerCode == wmsTask.ContainerCode && z.LocationVsContainerStatus == CommonStatus.ENABLE);
                    wmsContainerPlace.LocationVsContainerStatus = CommonStatus.DELETED;
                    await _wareLocationVsContainer.UpdateAsync(wmsContainerPlace);
                    await _wareLocationVsContainer.InsertAsync(new WareLocationVsContainer()
                    {
                        LocationId = ToPlace.Id,
                        LocationCode = ToPlace.Code,
                        ContainerId = wmsContainer.Id,
                        ContainerCode = wmsContainer.Code,
                        LocationVsContainerStatus = CommonStatus.ENABLE
                    });
                    //库存库位更新
                    var stockModel = await _wareStock.Where(p => p.ContainerCode == wmsTask.ContainerCode && p.LocationCode == SourcePlace.Code).ToListAsync();
                    foreach (var item in stockModel)
                    {
                        item.LocationCode = ToPlace.Code;
                        await _wareStock.UpdateAsync(item);
                    }
                }
            }

            await _wareTask.UpdateAsync(wmsTask);
        }


        /// <summary>
        /// 取消任务 wms上直接进行删除操作
        /// </summary>
        /// <returns></returns>
        [HttpPost("CancelTask")]
        [UnitOfWork]
        [AllowAnonymous]
        public async Task CancelTask([FromBody] FinishTaskInput input)
        {
            // 写日志文件
            Log.Error("[Finish]接收参数:" + input.ToJson());

            // 根据任务号查询任务信息
            var wmsTask = await _wareTask.FirstOrDefaultAsync(z => z.TaskNo == input.TaskNo);
            if (wmsTask == null) throw Oops.Oh(errorMessage: "任务不存在或已完成！");
            wmsTask.IsRead = false;
            // 查询托盘信息
            var wmsContainer = await _wareContainer.FirstOrDefaultAsync(z => z.Code == wmsTask.ContainerCode);
            if (wmsContainer == null) throw Oops.Oh("托盘不存在！");
            //入库完成
            if (wmsTask.TaskType == TaskType.In)
            {
                //库位信息
                var wmsPlace = await _wareLocation.DetachedEntities.Where(z => z.Code == wmsTask.ToLocationCode).ProjectToType<WareLocation>().FirstOrDefaultAsync();
                if (wmsPlace != null)
                {
                    // 更新库位状态
                    wmsPlace.LocationStatus = LocationStatusEnum.kongxian;
                    await _wareLocation.UpdateAsync(wmsPlace);
                }
            }
            //出库堆垛机完成,执行库存，库位，托盘对应关系进行更新
            else if (wmsTask.TaskType == TaskType.Out)
            {
                // 查询库位信息
                var wmsPlace = await _wareLocation.FirstOrDefaultAsync(z => z.Code == wmsTask.FromLocationCode);
                if (wmsPlace == null) throw Oops.Oh("库位不存在!");
                wmsPlace.LocationStatus = LocationStatusEnum.cunhuo;
                await _wareLocation.UpdateAsync(wmsPlace);
            }
            else //移库
            {
                if (wmsTask.TaskType == TaskType.Move)
                {
                    // 起点库位信息
                    var SourcePlace = await _wareLocation.Where(z => z.Code == wmsTask.FromLocationCode).FirstOrDefaultAsync();
                    SourcePlace.LocationStatus = LocationStatusEnum.cunhuo;
                    await _wareLocation.UpdateAsync(SourcePlace);
                    //目标库位信息
                    var ToPlace = await _wareLocation.Where(z => z.Code == wmsTask.ToLocationCode).FirstOrDefaultAsync();
                    ToPlace.LocationStatus = LocationStatusEnum.kongxian;
                    await _wareLocation.UpdateAsync(ToPlace);
                }
            }

            await _wareTask.DeleteAsync(wmsTask);
        }



        #region  公用方法
        /// <summary>
        /// 根据巷道获取外侧第一排
        /// </summary>
        /// <param name="Aisle"></param>
        /// <returns></returns>
        public int GetOneRowByAisle(int Aisle)
        {
            return (Aisle - 1) * 4 + 1;
        }
        /// <summary>
        /// 根据巷道获取内侧第二排
        /// </summary>
        /// <param name="Aisle"></param>
        /// <returns></returns>
        public int GetTwoRowByAisle(int Aisle)
        {
            return (Aisle - 1) * 4 + 2;
        }
        /// <summary>
        /// 根据巷道获取外侧第二排
        /// </summary>
        /// <param name="Aisle"></param>
        /// <returns></returns>
        public int GetThreeRowByAisle(int Aisle)
        {
            return (Aisle - 1) * 4 + 3;
        }
        /// <summary>
        /// 根据巷道获取外侧第一排
        /// </summary>
        /// <param name="Aisle"></param>
        /// <returns></returns>
        public int GetFourRowByAisle(int Aisle)
        {
            return (Aisle - 1) * 4 + 4;
        }
        #endregion
    }
}
